home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / tools / czesc_2 / ispell-3.3ljr / ispell / tree.c < prev    next >
C/C++ Source or Header  |  1992-09-22  |  18KB  |  808 lines

  1. /*
  2.  * tree.c - a hash style dictionary for user's personal words
  3.  *
  4.  * Pace Willisson, 1983
  5.  * Hash support added by Geoff Kuenning, 1987
  6.  */
  7.  
  8. #include <stdlib.h>
  9. #undef _STRICT_ANSI
  10. #include <stdio.h>
  11. #define _STRICT_ANSI
  12. #include <ctype.h>
  13. #include <string.h>
  14. #include "config.h"
  15. #include "ispell.h"
  16.  
  17. static struct dent *tinsert (char *word, struct dent *proto, int keep);
  18. static void toutent (struct dent *cent);
  19. static void toutword (char *word, struct dent *cent);
  20. static void flagout (int flag);
  21.  
  22. static int cantexpand = 0;    /* NZ if an expansion fails */
  23. static struct dent *htab = NULL;/* Hash table for our stuff */
  24. static int hsize = 0;        /* Space available in hash table */
  25. static int hcount = 0;        /* Number of items in hash table */
  26.  
  27. /*
  28.  * Hash table sizes.  Prime is probably a good idea, though in truth I
  29.  * whipped the algorithm up on the spot rather than looking it up, so
  30.  * who knows what's really best?  If we overflow the table, we just
  31.  * use a double-and-add-1 algorithm.
  32.  *
  33.  * The strange pattern in the table is because this table is sometimes
  34.  * used with huge dictionaries, and we want to get the table bigger fast.
  35.  * 23003 just happens to be such that the original dict.191 will fill
  36.  * the table to just under 70%.  31469 is similarly selected for dict.191
  37.  * combined with /usr/dict/words.  The other numbers are on 10000-word
  38.  * intervals starting at 30000.  (The table is still valid if MAXPCT
  39.  * is changed, but the dictionary sizes will no longer fall on neat
  40.  * boundaries).
  41.  */
  42. static int goodsizes[] =
  43. {
  44.   53, 223, 907,
  45. #if ((BIG_DICT * 100) / MAXPCT) <= 23003
  46.   23003,            /* ~16000 words */
  47. #endif
  48. #if ((BIG_DICT * 100) / MAXPCT) <= 31469
  49.   31469,            /* ~22000 words */
  50. #endif
  51. #if ((BIG_DICT * 100) / MAXPCT) <= 42859
  52.   42859,            /* ~30000 words */
  53. #endif
  54. #if ((BIG_DICT * 100) / MAXPCT) <= 57143
  55.   57143,            /* ~40000 words */
  56. #endif
  57.   71429                /* ~50000 words */
  58. };
  59.  
  60. static char personaldict[MAXPATHLEN];
  61. static FILE *dictf;
  62. static newwords = 0;
  63.  
  64. extern struct dent *hashtbl;
  65. extern int hashsize;
  66.  
  67. void treeinit (char *p)
  68. {
  69.   register char *h;
  70.   char *orig;
  71.   char buf[BUFSIZ];
  72.   register struct dent *dp;
  73.  
  74.   /*
  75.   ** if p exists and begins with '/' we don't really need HOME,
  76.   ** but it's not very likely that HOME isn't set anyway.
  77.   */
  78.   orig = p;
  79.   if (p == NULL)
  80.     p = getenv (PDICTVAR);
  81.   if ((h = getenv ("HOME")) == NULL)
  82.     h = LIBDIR;
  83.  
  84.   if (p == NULL)
  85.     sprintf (personaldict, "%s%s", h, DEFPDICT);
  86.   else
  87.     {
  88.       if (*p == '/')
  89.     strcpy (personaldict, p);
  90.       else
  91.     {
  92.       /*
  93.       ** The user gave us a relative pathname.  How we
  94.       ** interpret it depends on how it was given:
  95.       **
  96.       ** -p switch:  as-is first, then $HOME/name
  97.       ** PDICTVAR:   $HOME/name first, then as-is
  98.       **/
  99.       if (orig == NULL)
  100.         sprintf (personaldict, "%s/%s", h, p);
  101.       else            /* -p switch */
  102.         strcpy (personaldict, p);
  103.     }
  104.     }
  105.  
  106.   if ((dictf = fopen (personaldict, "r")) == NULL)
  107.     {
  108.       /* The file doesn't exist. */
  109.       if (p != NULL)
  110.     {
  111.       /* If pathname is relative, try another place */
  112.       if (*p != '/')
  113.         {
  114.           if (orig == NULL)
  115.         strcpy (personaldict, p);
  116.           else        /* -p switch */
  117.         sprintf (personaldict, "%s/%s", h, p);
  118.           dictf = fopen (personaldict, "r");
  119.         }
  120.       if (dictf == NULL)
  121.         {
  122.           (void) fprintf (stderr, "Couldn't open ");
  123.           perror (p);
  124.           if (*p != '/')
  125.         {
  126.           /*
  127.           ** Restore the preferred default, so
  128.           ** that output will go th the right
  129.           ** place.
  130.           */
  131.           if (orig == NULL)
  132.             sprintf (personaldict,
  133.                  "%s/%s", h, p);
  134.           else        /* -p switch */
  135.             strcpy (personaldict, p);
  136.         }
  137.         }
  138.     }
  139.       /* If the name wasn't specified explicitly, we don't object */
  140.       return;
  141.     }
  142.  
  143.   while (fgets (buf, sizeof buf, dictf) != NULL)
  144.     {
  145.       int len = strlen (buf) - 1;
  146.  
  147.       if (buf[len] == '\n')
  148.     buf[len] = '\0';
  149.       if ((h = strchr (buf, '/')) != NULL)
  150.     *h++ = '\0';
  151.       dp = treeinsert (buf, 1);
  152.       if (h != NULL)
  153.     {
  154.       while (*h != '\0' && *h != '\n')
  155.         {
  156.           if (islower (*h))
  157.         *h = toupper (*h);
  158.           switch (*h++)
  159.         {
  160.         case 'D':
  161.           dp->d_flag = 1;
  162.           break;
  163.         case 'G':
  164.           dp->g_flag = 1;
  165.           break;
  166.         case 'H':
  167.           dp->h_flag = 1;
  168.           break;
  169.         case 'J':
  170.           dp->j_flag = 1;
  171.           break;
  172.         case 'M':
  173.           dp->m_flag = 1;
  174.           break;
  175.         case 'N':
  176.           dp->n_flag = 1;
  177.           break;
  178.         case 'P':
  179.           dp->p_flag = 1;
  180.           break;
  181.         case 'R':
  182.           dp->r_flag = 1;
  183.           break;
  184.         case 'S':
  185.           dp->s_flag = 1;
  186.           break;
  187.         case 'T':
  188.           dp->t_flag = 1;
  189.           break;
  190.         case 'V':
  191.           dp->v_flag = 1;
  192.           break;
  193.         case 'X':
  194.           dp->x_flag = 1;
  195.           break;
  196.         case 'Y':
  197.           dp->y_flag = 1;
  198.           break;
  199.         case 'Z':
  200.           dp->z_flag = 1;
  201.           break;
  202.         default:
  203.           fprintf (stderr,
  204.              "Illegal flag in personal dictionary - %c (word %s)\n",
  205.                h[-1], buf);
  206.           break;
  207.         }
  208.           /* Accept old-format dicts with extra slashes */
  209.           if (*h == '/')
  210.         h++;
  211.         }
  212.     }
  213.     }
  214.  
  215.   fclose (dictf);
  216.  
  217.   newwords = 0;
  218.  
  219.   if (!lflag && !aflag && access (personaldict, 2) < 0)
  220.     fprintf (stderr,
  221.          "Warning: Cannot update personal dictionary (%s)\n",
  222.          personaldict);
  223. }
  224.  
  225. struct dent *treeinsert (char *word, int keep)
  226. {
  227.   register int i;
  228.   register struct dent *dp;
  229.   struct dent *olddp;
  230.   struct dent *oldhtab;
  231.   int oldhsize;
  232.   char nword[BUFSIZ];
  233.   int len;
  234. #ifdef CAPITALIZE
  235.   register char *cp;
  236.   char *saveword;
  237.   int capspace;
  238. #endif
  239.  
  240.   strcpy (nword, word);
  241.   upcase (nword);
  242.   len = strlen (nword);
  243.   if ((dp = lookup (nword, len, 0)) != NULL)
  244.     dp->keep = keep;
  245.   /*
  246.    * Expand hash table when it is MAXPCT % full.
  247.    */
  248.   else if (!cantexpand && (hcount * 100) / MAXPCT >= hsize)
  249.     {
  250.       oldhsize = hsize;
  251.       oldhtab = htab;
  252.       for (i = 0; i < sizeof goodsizes / sizeof (goodsizes[0]); i++)
  253.     if (goodsizes[i] > hsize)
  254.       break;
  255.       if (i >= sizeof goodsizes / sizeof goodsizes[0])
  256.     hsize += hsize + 1;
  257.       else
  258.     hsize = goodsizes[i];
  259.       htab = (struct dent *) calloc (hsize, sizeof (struct dent));
  260.       if (htab == NULL)
  261.     {
  262.       (void) fprintf (stderr,
  263.               "Ran out of space for personal dictionary\n");
  264.       /*
  265.        * Try to continue anyway, since our overflow
  266.        * algorithm can handle an overfull (100%+) table,
  267.        * and the malloc very likely failed because we
  268.        * already have such a huge table, so small mallocs
  269.        * for overflow entries will still work.
  270.        */
  271.       if (oldhtab == NULL)
  272.         exit (1);        /* No old table, can't go on */
  273.       (void) fprintf (stderr,
  274.               "Continuing anyway (with reduced performance).\n");
  275.       cantexpand = 1;    /* Suppress further messages */
  276.       hsize = oldhsize;    /* Put this back how the were */
  277.       htab = oldhtab;    /* ... */
  278.       newwords = 1;        /* And pretend it worked */
  279.       return tinsert (nword, (struct dent *) NULL, keep);
  280.     }
  281.       else
  282.     {
  283.       /*
  284.        * Re-insert old entries into new table
  285.        */
  286.       for (i = 0; i < oldhsize; i++)
  287.         {
  288.           dp = &oldhtab[i];
  289.           if (oldhtab[i].used)
  290.         {
  291.           tinsert ((char *) NULL, dp, 0);
  292.           dp = dp->next;
  293.           while (dp != NULL)
  294.             {
  295.               tinsert ((char *) NULL, dp, 0);
  296.               olddp = dp;
  297.               dp = dp->next;
  298.               free ((char *) olddp);
  299.             }
  300.         }
  301.         }
  302.       if (oldhtab != NULL)
  303.         free ((char *) oldhtab);
  304.       dp = NULL;        /* This will force the insert below */
  305.     }
  306.     }
  307.   newwords |= keep;
  308.   if (dp == NULL)
  309.     dp = tinsert (nword, (struct dent *) NULL, keep);
  310. #ifdef CAPITALIZE
  311.   if (dp == NULL)
  312.     return NULL;
  313.   /*
  314.   ** Figure out the capitalization rules from the
  315.   ** capitalization of the sample entry.  If the sample is
  316.   ** all caps, we don't change the existing flags, since
  317.   ** all-caps gives us no information.  Tinsert initializes
  318.   ** new entries with "allcaps" set, so if the word is truly
  319.   ** required to appear in capitals, the correct result
  320.   ** will be achieved.
  321.   */
  322.   for (cp = word; *cp; cp++)
  323.     {
  324.       if (mylower (*cp))
  325.     break;
  326.     }
  327.   if (*cp)
  328.     {
  329.       /*
  330.       ** Sample entry has at least some lowercase.  See if
  331.       ** the case is mixed.
  332.       */
  333.       for (cp = word; *cp; cp++)
  334.     {
  335.       if (myupper (*cp))
  336.         break;
  337.     }
  338.       if (*cp == '\0' && !dp->followcase)
  339.     {
  340.       /*
  341.       ** Sample entry is all lowercase, and word is not
  342.       ** followcase.  Clear all of the capitalization flags.
  343.       */
  344.       dp->allcaps = 0;
  345.       dp->capitalize = 0;
  346.       if (keep)
  347.         {
  348.           dp->k_allcaps = 0;
  349.           dp->k_capitalize = 0;
  350.           dp->k_followcase = 0;
  351.         }
  352.     }
  353.       else
  354.     {
  355.       /*
  356.       ** The sample entry is mixed case (or all-lower and the
  357.       ** entry is already followcase).  If it's simply
  358.       ** capitalized, set the capitalize flag and that's that.
  359.       */
  360.       for (cp = word + 1; *cp && !myupper (*cp);)
  361.         cp++;
  362.       if (*cp == 0 && myupper (*word))
  363.         {
  364.           dp->allcaps = 0;
  365.           dp->capitalize = 1;
  366.           if (keep)
  367.         {
  368.           dp->k_allcaps = 0;
  369.           dp->k_capitalize = 1;
  370.         }
  371.         }
  372.       else
  373.         {
  374.           /*
  375.           ** The sample entry is followcase.  Make the
  376.           ** dictionary entry followcase if necessary.
  377.           */
  378.           if (!dp->followcase)
  379.         {
  380.           dp->followcase = 1;
  381.           if (keep)
  382.             dp->k_followcase = 1;
  383.           capspace = 2 * len + 4;
  384.           if (dp->word >= hashstrings
  385.               && dp->word <=
  386.               hashstrings
  387.               + hashheader.stringsize)
  388.             {
  389.               cp = dp->word;
  390.               dp->word = malloc (capspace);
  391.               if (dp->word)
  392.             strcpy (dp->word, cp);
  393.             }
  394.           else
  395.             dp->word = realloc (dp->word,
  396.                     capspace);
  397.           if (dp->word == NULL)
  398.             {
  399.               fprintf (stderr,
  400.                    "Ran out of space for personal dictionary\n");
  401.               exit (1);
  402.             }
  403.           cp = dp->word + len + 1;
  404.           if (dp->capitalize || dp->allcaps)
  405.             *cp++ = 0;
  406.           else
  407.             {
  408.               *cp++ = 1;
  409.               strcpy (cp + 1, dp->word);
  410.               lowcase (cp + 1);
  411.             }
  412.           *cp = dp->keep ? '+' : '-';
  413.         }
  414.           dp->allcaps = 0;
  415.           if (keep)
  416.         dp->k_allcaps = 0;
  417.           cp = dp->word + len + 1;
  418.           /* See if the capitalization is already there */
  419.           for (i = 0, saveword = cp + 1;
  420.            i < (*cp & 0xFF);
  421.            i++)
  422.         {
  423.           if (strcmp (saveword + 1, word) == 0)
  424.             break;
  425.           saveword += len + 2;
  426.         }
  427.           if (i != (*cp & 0xFF))
  428.         {
  429.           if (keep)
  430.             *saveword = '+';
  431.         }
  432.           else
  433.         {
  434.           /* Add a new capitalization */
  435.           (*cp)++;
  436.           capspace = (cp - dp->word + 1)
  437.             * ((*cp & 0xFF) + 1);
  438.           if (dp->word >= hashstrings
  439.               && dp->word <=
  440.               hashstrings + hashheader.stringsize)
  441.             {
  442.               saveword = dp->word;
  443.               dp->word = malloc (capspace);
  444.               if (dp->word)
  445.             {
  446.               cp = dp->word;
  447.               while (--capspace >= 0)
  448.                 *cp++ =
  449.                   *saveword++;
  450.             }
  451.             }
  452.           else
  453.             dp->word =
  454.               realloc (dp->word, capspace);
  455.           if (dp->word == NULL)
  456.             {
  457.               fprintf (stderr,
  458.                    "Ran out of space for personal dictionary\n");
  459.               exit (1);
  460.             }
  461.           cp = dp->word + len + 1;
  462.           cp += ((*cp & 0xFF) - 1)
  463.             * (cp - dp->word + 1) + 1;
  464.           *cp++ = keep ? '+' : '-';
  465.           strcpy (cp, word);
  466.         }
  467.         }
  468.     }
  469.     }
  470. #endif
  471.   return dp;
  472. }
  473.  
  474. static struct dent *tinsert (char *word, struct dent *proto, int keep)
  475. {
  476.   register int hcode;
  477.   register struct dent *hp;    /* Next trial entry in hash table */
  478.   register struct dent *php;    /* Previous value of hp, for chaining */
  479.  
  480.   if (word == NULL)
  481.     word = proto->word;
  482.   hcode = hash (word, strlen (word), hsize);
  483.   php = NULL;
  484.   hp = &htab[hcode];
  485.   if (hp->used)
  486.     {
  487.       while (hp != NULL)
  488.     {
  489.       if (strcmp (word, hp->word) == 0)
  490.         {
  491.           if (keep)
  492.         hp->keep = 1;
  493.           return hp;
  494.         }
  495.       php = hp;
  496.       hp = hp->next;
  497.     }
  498.       hp = (struct dent *) calloc (1, sizeof (struct dent));
  499.       if (hp == NULL)
  500.     {
  501.       (void) fprintf (stderr,
  502.               "Ran out of space for personal dictionary\n");
  503.       exit (1);
  504.     }
  505.     }
  506.   if (proto != NULL)
  507.     {
  508.       *hp = *proto;
  509.       if (php != NULL)
  510.     php->next = hp;
  511.       hp->next = NULL;
  512.       return &htab[hcode];
  513.     }
  514.   else
  515.     {
  516.       if (php != NULL)
  517.     php->next = hp;
  518.       hp->word = (char *) malloc (strlen (word) + 1);
  519.       if (hp->word == NULL)
  520.     {
  521.       (void) fprintf (stderr,
  522.               "Ran out of space for personal dictionary\n");
  523.       exit (1);
  524.     }
  525.       strcpy (hp->word, word);
  526.       hp->used = 1;
  527.       hp->next = NULL;
  528.       hp->d_flag = 0;
  529.       hp->g_flag = 0;
  530.       hp->h_flag = 0;
  531.       hp->j_flag = 0;
  532.       hp->m_flag = 0;
  533.       hp->n_flag = 0;
  534.       hp->p_flag = 0;
  535.       hp->r_flag = 0;
  536.       hp->s_flag = 0;
  537.       hp->t_flag = 0;
  538.       hp->v_flag = 0;
  539.       hp->x_flag = 0;
  540.       hp->y_flag = 0;
  541.       hp->z_flag = 0;
  542. #ifdef CAPITALIZE
  543.       hp->allcaps = 1;        /* Assume word is all-caps */
  544.       hp->k_allcaps = 1;
  545.       hp->capitalize = 0;
  546.       hp->k_capitalize = 0;
  547.       hp->followcase = 0;
  548.       hp->k_followcase = 0;
  549. #endif
  550.       hp->keep = keep;
  551.       hcount++;
  552.       return (hp);
  553.     }
  554. }
  555.  
  556. struct dent *treelookup (char *word)
  557. {
  558.   register int hcode;
  559.   register struct dent *hp;
  560.   char nword[BUFSIZ];
  561.  
  562.   if (hsize <= 0)
  563.     return NULL;
  564.   strcpy (nword, word);
  565.   hcode = hash (nword, strlen (nword), hsize);
  566.   hp = &htab[hcode];
  567.   while (hp != NULL && hp->used)
  568.     {
  569.       if (strcmp (nword, hp->word) == 0)
  570.     break;
  571.       hp = hp->next;
  572.     }
  573.   if (hp != NULL && hp->used)
  574.     return hp;
  575.   else
  576.     return NULL;
  577. }
  578.  
  579. #if SORTPERSONAL != 0
  580. /* Comparison routine for sorting the personal dictionary with qsort */
  581. int pdictcmp (struct dent **enta, struct dent **entb)
  582. {
  583.   return casecmp ((*enta)->word, (*entb)->word);
  584. }
  585.  
  586. #endif
  587.  
  588. void treeoutput (void)
  589. {
  590.   register struct dent *cent;    /* Current entry */
  591.   register struct dent *lent;    /* Linked entry */
  592. #if SORTPERSONAL != 0
  593.   int pdictsize;        /* Number of entries to write */
  594.   struct dent **sortlist;    /* List of entries to be sorted */
  595.   register struct dent **sortptr;    /* Handy pointer into sortlist */
  596. #endif
  597.   register struct dent *ehtab;    /* End of htab, for quick looping */
  598.  
  599.   if (newwords == 0)
  600.     return;
  601.  
  602.   if ((dictf = fopen (personaldict, "w")) == NULL)
  603.     {
  604.       fprintf (stderr, "Can't create %s\n", personaldict);
  605.       return;
  606.     }
  607.  
  608. #if SORTPERSONAL != 0
  609.   /*
  610.   ** If we are going to sort the personal dictionary, we must know
  611.   ** how many items are going to be sorted.
  612.   */
  613.   if (hcount >= SORTPERSONAL)
  614.     sortlist = NULL;
  615.   else
  616.     {
  617.       pdictsize = 0;
  618.       for (cent = htab, ehtab = htab + hsize;
  619.        cent < ehtab;
  620.        cent++)
  621.     {
  622.       for (lent = cent; lent != NULL; lent = lent->next)
  623.         {
  624.           if (lent->used && lent->keep)
  625.         pdictsize++;
  626.         }
  627.     }
  628.       for (cent = hashtbl, ehtab = hashtbl + hashsize;
  629.        cent < ehtab;
  630.        cent++)
  631.     {
  632.       if (cent->keep && cent->used)
  633.         pdictsize++;
  634.     }
  635.       sortlist = (struct dent **)
  636.     malloc (pdictsize * sizeof (struct dent));
  637.     }
  638.   if (sortlist == NULL)
  639.     {
  640. #endif
  641.       for (cent = htab, ehtab = htab + hsize;
  642.        cent < ehtab;
  643.        cent++)
  644.     {
  645.       for (lent = cent; lent != NULL; lent = lent->next)
  646.         {
  647.           if (lent->used && lent->keep)
  648.         toutent (lent);
  649.         }
  650.     }
  651.       for (cent = hashtbl, ehtab = hashtbl + hashsize;
  652.        cent < ehtab;
  653.        cent++)
  654.     {
  655.       if (cent->used && cent->keep)
  656.         toutent (cent);
  657.     }
  658. #if SORTPERSONAL != 0
  659.       return;
  660.     }
  661.   /*
  662.   ** Produce dictionary in sorted order.  We used to do this
  663.   ** destructively, but that turns out to fail because in some modes
  664.   ** the dictionary is written more than once.  So we build an
  665.   ** auxiliary pointer table (in sortlist) and sort that.  This
  666.   ** is faster anyway, though it uses more memory.
  667.   */
  668.   sortptr = sortlist;
  669.   for (cent = htab, ehtab = htab + hsize; cent < ehtab; cent++)
  670.     {
  671.       for (lent = cent; lent != NULL; lent = lent->next)
  672.     {
  673.       if (lent->used && lent->keep)
  674.         *sortptr++ = lent;
  675.     }
  676.     }
  677.   for (cent = hashtbl, ehtab = hashtbl + hashsize;
  678.        cent < ehtab;
  679.        cent++)
  680.     {
  681.       if (cent->used && cent->keep)
  682.     *sortptr++ = cent;
  683.     }
  684.   /* Sort the list */
  685.   qsort ((char *) sortlist, pdictsize, sizeof (sortlist[0]), pdictcmp);
  686.   /* Write it out */
  687.   for (sortptr = sortlist; --pdictsize >= 0;)
  688.     toutent (*sortptr++);
  689.   free ((char *) sortlist);
  690. #endif
  691.  
  692.   newwords = 0;
  693.  
  694.   fclose (dictf);
  695. }
  696.  
  697. static int hasslash;
  698.  
  699. static void toutent (struct dent *cent)
  700. {
  701. #ifdef CAPITALIZE
  702.   register char *cp;
  703.   int len;
  704.   register int wcount;
  705.   char wbuf[WORDLEN + 1];
  706.  
  707.   strcpy (wbuf, cent->word);
  708.   if (cent->k_followcase)
  709.     {
  710.       if (cent->k_capitalize)
  711.     {
  712.       lowcase (wbuf);
  713.       if (mylower (wbuf[0]))
  714.         wbuf[0] = toupper (wbuf[0]);
  715.       toutword (wbuf, cent);
  716.     }
  717.       len = strlen (wbuf) + 1;
  718.       cp = cent->word + len;
  719.       wcount = *cp++ & 0xFF;
  720.       while (--wcount >= 0)
  721.     {
  722.       if (*cp++ == '+')
  723.         toutword (cp, cent);
  724.       cp += len;
  725.     }
  726.     }
  727.   else
  728.     {
  729.       if (!cent->k_allcaps)
  730.     lowcase (wbuf);
  731.       if (cent->k_capitalize && mylower (wbuf[0]))
  732.     wbuf[0] = toupper (wbuf[0]);
  733.       toutword (wbuf, cent);
  734.     }
  735. #else
  736.   toutword (cent->word, cent);
  737. #endif
  738. }
  739.  
  740. static void toutword (char *word, struct dent *cent)
  741. {
  742.   hasslash = 0;
  743.   fprintf (dictf, "%s", word);
  744.   if (cent->d_flag)
  745.     flagout ('D');
  746.   if (cent->g_flag)
  747.     flagout ('G');
  748.   if (cent->h_flag)
  749.     flagout ('H');
  750.   if (cent->j_flag)
  751.     flagout ('J');
  752.   if (cent->m_flag)
  753.     flagout ('M');
  754.   if (cent->n_flag)
  755.     flagout ('N');
  756.   if (cent->p_flag)
  757.     flagout ('P');
  758.   if (cent->r_flag)
  759.     flagout ('R');
  760.   if (cent->s_flag)
  761.     flagout ('S');
  762.   if (cent->t_flag)
  763.     flagout ('T');
  764.   if (cent->v_flag)
  765.     flagout ('V');
  766.   if (cent->x_flag)
  767.     flagout ('X');
  768.   if (cent->y_flag)
  769.     flagout ('Y');
  770.   if (cent->z_flag)
  771.     flagout ('Z');
  772.   fprintf (dictf, "\n");
  773. }
  774.  
  775. static void flagout (int flag)
  776. {
  777.   if (!hasslash)
  778.     putc ('/', dictf);
  779.   hasslash = 1;
  780.   putc (flag, dictf);
  781. }
  782.  
  783. char *upcase (char *s)
  784. {
  785.   register char *os = s;
  786.  
  787.   while (*s)
  788.     {
  789.       if (mylower (*s))
  790.     *s = toupper (*s);
  791.       s++;
  792.     }
  793.   return (os);
  794. }
  795.  
  796. char *lowcase (char *s)
  797. {
  798.   register char *os = s;
  799.  
  800.   while (*s)
  801.     {
  802.       if (myupper (*s))
  803.     *s = tolower (*s);
  804.       s++;
  805.     }
  806.   return (os);
  807. }
  808.